home *** CD-ROM | disk | FTP | other *** search
/ PC Media 4 / PC MEDIA CD04.iso / share / prog / rzsz0717 / rz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-16  |  28.2 KB  |  1,316 lines

  1. #define VERSION "3.38 06-03-94"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*
  5.  *
  6.  * rz.c By Chuck Forsberg
  7.  *    Copyright 1994 Omen Technology Inc All Rights Reserved
  8.  *
  9.  * A program for Unix to receive files and commands from computers running
  10.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  11.  *  rz uses Unix buffered input to reduce wasted CPU time.
  12.  *
  13.  * 
  14.  *********************************************************************
  15.  *********************************************************************
  16.  * 
  17.  *
  18.  *    This version implements numerous enhancements including ZMODEM
  19.  *    Run Length Encoding and variable length headers.  These
  20.  *    features were not funded by the original Telenet development
  21.  *    contract.
  22.  * 
  23.  * 
  24.  * This software may be freely used for educational (didactic
  25.  * only) purposes.  "Didactic" means it is used as a study item
  26.  * in a course teaching the workings of computer protocols.
  27.  * 
  28.  * This software may also be freely used to support file transfer
  29.  * operations to or from duly licensed Omen Technology products.
  30.  * This includes DSZ, GSZ, ZCOMM, Professional-YAM and PowerCom.
  31.  * Institutions desiring to use rz/sz this way should add the
  32.  * following to the sz compile line:    -DCOMPL
  33.  * Programs based on stolen or public domain ZMODEM materials are
  34.  * not included.  Use with other commercial or shareware programs
  35.  * (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
  36.  * 
  37.  *
  38.  *  Any programs which incorporate part or all of this code must be
  39.  *  provided in source form with this notice intact except by
  40.  *  prior written permission from Omen Technology Incorporated.
  41.  *  This includes compiled executables of this program.
  42.  *
  43.  *   The .doc files and the file "mailer.rz" must also be included.
  44.  * 
  45.  * Use of this software for commercial or administrative purposes
  46.  * except when exclusively limited to interfacing Omen Technology
  47.  * products requires license payment of $20.00 US per user
  48.  * (less in quantity, see mailer.rz).  Use of this code by
  49.  * inclusion, decompilation, reverse engineering or any other means
  50.  * constitutes agreement to these conditions and acceptance of
  51.  * liability to license the materials and payment of reasonable
  52.  * legal costs necessary to enforce this license agreement.
  53.  *
  54.  *
  55.  *        Omen Technology Inc
  56.  *        Post Office Box 4681
  57.  *        Portland OR 97208
  58.  *
  59.  *    This code is made available in the hope it will be useful,
  60.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  61.  *    DAMAGES OF ANY KIND.
  62.  *
  63.  *
  64.  *  -DMD may be added to compiler command line to compile in
  65.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  66.  *
  67.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  68.  */
  69.  
  70. char *Copyrrz = "Copyright 1994 Omen Technology Inc All Rights Reserved";
  71.  
  72.  
  73. #define LOGFILE "/tmp/rzlog"
  74. #define LOGFILE2 "rzlog"
  75. #include <stdio.h>
  76. #include <signal.h>
  77. #include <ctype.h>
  78. #include <errno.h>
  79. extern int errno;
  80.  
  81. #define OK 0
  82. #define FALSE 0
  83. #define TRUE 1
  84. #define ERROR (-1)
  85.  
  86. /*
  87.  * Max value for HOWMANY is 255.
  88.  *   A larger value reduces system overhead but may evoke kernel bugs.
  89.  */
  90. #ifndef HOWMANY
  91. #define HOWMANY 96
  92. #endif
  93.  
  94. /* Ward Christensen / CP/M parameters - Don't change these! */
  95. #define ENQ 005
  96. #define CAN ('X'&037)
  97. #define XOFF ('s'&037)
  98. #define XON ('q'&037)
  99. #define SOH 1
  100. #define STX 2
  101. #define EOT 4
  102. #define ACK 6
  103. #define NAK 025
  104. #define CPMEOF 032
  105. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  106. #define TIMEOUT (-2)
  107. #define RCDO (-3)
  108. #define GCOUNT (-4)
  109. #define ERRORMAX 5
  110. #define RETRYMAX 5
  111. #define WCEOT (-10)
  112. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  113. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  114.  
  115. int Zmodem=0;        /* ZMODEM protocol requested */
  116. int Nozmodem = 0;    /* If invoked as "rb" */
  117. unsigned Baudrate = 9600;
  118.  
  119.  
  120. #include "rbsb.c"    /* most of the system dependent stuff here */
  121. #include "crctab.c"
  122. char endmsg[90] = {0};    /* Possible message to display on exit */
  123. char Zsendmask[33];    /* Additional control chars to mask */
  124.  
  125. char *substr();
  126. FILE *fout;
  127.  
  128. /*
  129.  * Routine to calculate the free bytes on the current file system
  130.  *  ~0 means many free bytes (unknown)
  131.  */
  132. long getfree()
  133. {
  134.     return(2147483647);    /* many free bytes ... */
  135. }
  136.  
  137. int Lastrx;
  138. long rxbytes;
  139. int Crcflg;
  140. int Firstsec;
  141. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  142. int errors;
  143. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  144.  
  145. #define DEFBYTL 2000000000L    /* default rx file size */
  146. long Bytesleft;    /* number of bytes of incoming file left */
  147. long Modtime;        /* Unix style mod time for incoming file */
  148. int Filemode;        /* Unix style mode for incoming file */
  149. long Totalleft;
  150. long Filesleft;
  151. char Pathname[PATHLEN];
  152. char *Progname;        /* the name by which we were called */
  153.  
  154. int Batch=0;
  155. int Thisbinary;        /* current file is to be received in bin mode */
  156. int Rxbinary=FALSE;    /* receive all files in bin mode */
  157. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  158. int Blklen;        /* record length of received packets */
  159.  
  160. #ifdef SEGMENTS
  161. int chinseg = 0;    /* Number of characters received in this data seg */
  162. char secbuf[1+(SEGMENTS+1)*1024];
  163. #else
  164. char secbuf[1025];
  165. #endif
  166.  
  167.  
  168. time_t timep[2];
  169. char Lzmanag;        /* Local file management request */
  170. char Lzconv;        /* Local ZMODEM file conversion request */
  171. char zconv;        /* ZMODEM file conversion request */
  172. char zmanag;        /* ZMODEM file management request */
  173. char ztrans;        /* ZMODEM file transport request */
  174. int Zctlesc;        /* Encode control characters */
  175. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  176.  
  177. /*
  178.  * Log an error
  179.  */
  180. /*VARARGS1*/
  181. void
  182. zperr(s,p,u)
  183. char *s, *p, *u;
  184. {
  185.     if (Verbose <= 0)
  186.         return;
  187.     fprintf(stderr, "Retry %d: ", errors);
  188.     fprintf(stderr, s, p, u);
  189.     fprintf(stderr, "\n");
  190. }
  191.  
  192. #include "zm.c"
  193. #include "zmr.c"
  194.  
  195. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  196.  
  197. /* called by signal interrupt or terminate to clean things up */
  198. void
  199. bibi(n)
  200. {
  201.     if (Zmodem)
  202.         zmputs(Attn);
  203.     canit(); mode(0);
  204.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  205.     exit(3);
  206. }
  207.  
  208. main(argc, argv)
  209. char *argv[];
  210. {
  211.     register char *cp;
  212.     register npats;
  213.     char *virgin, **patts;
  214.     int exitcode = 0;
  215.  
  216.     Rxtimeout = 100;
  217.     setbuf(stderr, NULL);
  218.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  219.         Restricted=TRUE;
  220.  
  221.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  222.     inittty();
  223.     npats = 0;
  224.     while (--argc) {
  225.         cp = *++argv;
  226.         if (*cp == '-') {
  227.             ++cp;
  228.             while( *cp) {
  229.                 if (isdigit(*cp)) {
  230.                     ++cp;  continue;
  231.                 }
  232.                 switch(*cp++) {
  233.                 case '\\':
  234.                      *cp = toupper(*cp);  continue;
  235.                 case 'a':
  236.                     if (!Batch || Nozmodem)
  237.                         Rxascii=TRUE;
  238.                     else
  239.                         usage();
  240.                     break;
  241.                 case 't':
  242.                     if (isdigit(*cp))
  243.                         Rxtimeout = atoi(cp);
  244.                     else {
  245.                         if (--argc < 1)
  246.                             usage();
  247.                         Rxtimeout = atoi(*++argv);
  248.                     }
  249.                     if (Rxtimeout<1 || Rxtimeout>1000)
  250.                         usage();
  251.                     break;
  252.                 case 'w':
  253.                     if (isdigit(*cp))
  254.                         Zrwindow = atoi(cp);
  255.                     else {
  256.                         if (--argc < 1)
  257.                             usage();
  258.                         Zrwindow = atoi(*++argv);
  259.                     }
  260.                     break;
  261.                 case 'v':
  262.                     ++Verbose; break;
  263.                 default:
  264.                     usage();
  265.                 }
  266.             }
  267.         }
  268.         else if ( !npats && argc>0) {
  269.             if (argv[0][0]) {
  270.                 npats=argc;
  271.                 patts=argv;
  272.             }
  273.         }
  274.     }
  275.     if (npats > 1)
  276.         usage();
  277.     if (Batch && npats)
  278.         usage();
  279.     if (Verbose) {
  280.         if (freopen(LOGFILE, "a", stderr)==NULL)
  281.             if (freopen(LOGFILE2, "a", stderr)==NULL) {
  282.                 printf("Can't open log file!");
  283.                 exit(2);
  284.             }
  285.         setbuf(stderr, NULL);
  286.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  287.     }
  288.     vfile("%s %s for %s tty=%s\n", Progname, VERSION, OS, Nametty);
  289.     mode(1);
  290.     if (signal(SIGINT, bibi) == SIG_IGN) {
  291.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  292.     }
  293.     else {
  294.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  295.     }
  296.     signal(SIGTERM, bibi);
  297.     if (wcreceive(npats, patts)==ERROR) {
  298.         exitcode=1;
  299.         canit();
  300.     }
  301.     mode(0);
  302.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  303.         canit();
  304.     if (endmsg[0])
  305.         printf("  %s: %s\r\n", Progname, endmsg);
  306.     printf("%s %s finished.\r\n", Progname, VERSION);
  307.     fflush(stdout);
  308.     if(exitcode)
  309.         exit(1);
  310. #ifndef REGISTERED
  311.     /* Removing or disabling this code without registering is theft */
  312.     if (!Usevhdrs)  {
  313.         printf( "\n\n\nPlease read the License Agreement in rz.doc\n");
  314.         fflush(stdout);
  315.         sleep(10);
  316.     }
  317. #endif
  318.     exit(0);
  319.     /* NOTREACHED */
  320. }
  321.  
  322.  
  323. usage()
  324. {
  325.     fprintf(stderr,
  326.     "Receive Files and Commands with ZMODEM/YMODEM/XMODEM Protocol\n\n");
  327.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  328.       Progname, VERSION, OS);
  329.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n\n");
  330.     fprintf(stderr,"Usage:    rz [-v]        (ZMODEM)\n");
  331.     fprintf(stderr,"or    rb [-av]    (YMODEM)\n");
  332.     fprintf(stderr,"or    rc [-av] file    (XMODEM-CRC)\n");
  333.     fprintf(stderr,"or    rx [-av] file    (XMODEM)\n\n");
  334.     fprintf(stderr,
  335. "Supports the following incoming ZMODEM options given to the sending program:\n\
  336.     compression (-Z), binary (-b), ASCII CR/LF>NL (-a), newer(-n),\n\
  337.     newer+longer(-N), protect (-p), Crash Recovery (-r),\n\
  338.     clobber (-y), match+clobber (-Y),  and append (-+).\n\n");
  339.     fprintf(stderr,"Copyright (c) 1994 Omen Technology INC All Rights Reserved\n");
  340.     fprintf(stderr,
  341.     "See rz.doc for option descriptions and licensing information.\n\n");
  342.     fprintf(stderr,
  343.     "This program is designed to talk to terminal programs,\nnot to be called by one.\n");
  344.     fprintf(stderr,
  345.     "\nTechnical support hotline: 900-737-7836 (1-900-737-RTFM) $4.69/min.\n\n");
  346.     exit(2);
  347. }
  348.  
  349. /*
  350.  * Let's receive something already.
  351.  */
  352.  
  353. char *rbmsg = "%s ready. Type \"%s file ...\" to your modem program\n\r";
  354.  
  355. wcreceive(argc, argp)
  356. char **argp;
  357. {
  358.     register c;
  359.  
  360.     if (Batch || argc==0) {
  361.         Crcflg=1;
  362.         fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  363.         if (c=tryz()) {
  364.             if (c == ZCOMPL)
  365.                 return OK;
  366.             if (c == ERROR)
  367.                 goto fubar;
  368.             c = rzfiles();
  369.             if (c)
  370.                 goto fubar;
  371.         } else {
  372.             for (;;) {
  373.                 if (wcrxpn(secbuf)== ERROR)
  374.                     goto fubar;
  375.                 if (secbuf[0]==0)
  376.                     return OK;
  377.                 if (procheader(secbuf) == ERROR)
  378.                     goto fubar;
  379.                 if (wcrx()==ERROR)
  380.                     goto fubar;
  381.             }
  382.         }
  383.     } else {
  384.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  385.  
  386.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  387.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  388.         if ((fout=fopen(Pathname, "w")) == NULL)
  389.             return ERROR;
  390.         if (wcrx()==ERROR)
  391.             goto fubar;
  392.     }
  393.     return OK;
  394. fubar:
  395.     canit();
  396.     Modtime = 1;
  397.     if (fout)
  398.         fclose(fout);
  399.     if (Restricted) {
  400.         unlink(Pathname);
  401.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  402.     }
  403.     return ERROR;
  404. }
  405.  
  406.  
  407. /*
  408.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  409.  * Length is indeterminate as long as less than Blklen
  410.  * A null string represents no more files (YMODEM)
  411.  */
  412. wcrxpn(rpn)
  413. char *rpn;    /* receive a pathname */
  414. {
  415.     register c;
  416.  
  417.     purgeline();
  418.  
  419. et_tu:
  420.     Firstsec=TRUE;  Eofseen=FALSE;
  421.     sendline(Crcflg?WANTCRC:NAK);  flushmo();
  422.     Lleft=0;    /* Do read next time ... */
  423.     while ((c = wcgetsec(rpn, 100)) != 0) {
  424.         if (c == WCEOT) {
  425.             zperr( "Pathname fetch returned %d", c);
  426.             sendline(ACK);  flushmo();
  427.             Lleft=0;    /* Do read next time ... */
  428.             readline(1);
  429.             goto et_tu;
  430.         }
  431.         return ERROR;
  432.     }
  433.     sendline(ACK);  flushmo();
  434.     return OK;
  435. }
  436.  
  437. /*
  438.  * Adapted from CMODEM13.C, written by
  439.  * Jack M. Wierda and Roderick W. Hart
  440.  */
  441.  
  442. wcrx()
  443. {
  444.     register int sectnum, sectcurr;
  445.     register char sendchar;
  446.     int cblklen;            /* bytes to dump this block */
  447.  
  448.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  449.     sendchar=Crcflg?WANTCRC:NAK;
  450.  
  451.     for (;;) {
  452.         sendline(sendchar);    /* send it now, we're ready! */
  453.         flushmo();
  454.         Lleft=0;    /* Do read next time ... */
  455.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  456.         if (sectcurr==(sectnum+1 &0377)) {
  457.             sectnum++;
  458.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  459.             if (putsec(secbuf, cblklen)==ERROR)
  460.                 return ERROR;
  461.             if ((Bytesleft-=cblklen) < 0)
  462.                 Bytesleft = 0;
  463.             sendchar=ACK;
  464.         }
  465.         else if (sectcurr==(sectnum&0377)) {
  466.             zperr( "Received dup Sector");
  467.             sendchar=ACK;
  468.         }
  469.         else if (sectcurr==WCEOT) {
  470.             if (closeit())
  471.                 return ERROR;
  472.             sendline(ACK); flushmo();
  473.             Lleft=0;    /* Do read next time ... */
  474.             return OK;
  475.         }
  476.         else if (sectcurr==ERROR)
  477.             return ERROR;
  478.         else {
  479.             zperr( "Sync Error");
  480.             return ERROR;
  481.         }
  482.     }
  483.     /* NOTREACHED */
  484. }
  485.  
  486. /*
  487.  * Wcgetsec fetches a Ward Christensen type sector.
  488.  * Returns sector number encountered or ERROR if valid sector not received,
  489.  * or CAN CAN received
  490.  * or WCEOT if eot sector
  491.  * time is timeout for first char, set to 4 seconds thereafter
  492.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  493.  *    (Caller must do that when he is good and ready to get next sector)
  494.  */
  495.  
  496. wcgetsec(rxbuf, maxtime)
  497. char *rxbuf;
  498. int maxtime;
  499. {
  500.     register checksum, wcj, firstch;
  501.     register unsigned short oldcrc;
  502.     register char *p;
  503.     int sectcurr;
  504.  
  505.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  506.  
  507.         if ((firstch=readline(maxtime))==STX) {
  508.             Blklen=1024; goto get2;
  509.         }
  510.         if (firstch==SOH) {
  511.             Blklen=128;
  512. get2:
  513.             sectcurr=readline(1);
  514.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  515.                 oldcrc=checksum=0;
  516.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  517.                     if ((firstch=readline(1)) < 0)
  518.                         goto bilge;
  519.                     oldcrc=updcrc(firstch, oldcrc);
  520.                     checksum += (*p++ = firstch);
  521.                 }
  522.                 if ((firstch=readline(1)) < 0)
  523.                     goto bilge;
  524.                 if (Crcflg) {
  525.                     oldcrc=updcrc(firstch, oldcrc);
  526.                     if ((firstch=readline(1)) < 0)
  527.                         goto bilge;
  528.                     oldcrc=updcrc(firstch, oldcrc);
  529.                     if (oldcrc & 0xFFFF)
  530.                         zperr( "CRC");
  531.                     else {
  532.                         Firstsec=FALSE;
  533.                         return sectcurr;
  534.                     }
  535.                 }
  536.                 else if (((checksum-firstch)&0377)==0) {
  537.                     Firstsec=FALSE;
  538.                     return sectcurr;
  539.                 }
  540.                 else
  541.                     zperr( "Checksum");
  542.             }
  543.             else
  544.                 zperr("Sector number garbled");
  545.         }
  546.         /* make sure eot really is eot and not just mixmash */
  547.         else if (firstch==EOT && Lleft==0)
  548.             return WCEOT;
  549.         else if (firstch==CAN) {
  550.             if (Lastrx==CAN) {
  551.                 zperr( "Sender CANcelled");
  552.                 return ERROR;
  553.             } else {
  554.                 Lastrx=CAN;
  555.                 continue;
  556.             }
  557.         }
  558.         else if (firstch==TIMEOUT) {
  559.             if (Firstsec)
  560.                 goto humbug;
  561. bilge:
  562.             zperr( "TIMEOUT");
  563.         }
  564.         else
  565.             zperr( "Got 0%o sector header", firstch);
  566.  
  567. humbug:
  568.         Lastrx=0;
  569.         while(readline(1)!=TIMEOUT)
  570.             ;
  571.         if (Firstsec) {
  572.             sendline(Crcflg?WANTCRC:NAK);  flushmo();
  573.             Lleft=0;    /* Do read next time ... */
  574.         } else {
  575.             maxtime=40; sendline(NAK);  flushmo();
  576.             Lleft=0;    /* Do read next time ... */
  577.         }
  578.     }
  579.     /* try to stop the bubble machine. */
  580.     canit();
  581.     return ERROR;
  582. }
  583.  
  584.  
  585. /*
  586.  * Process incoming file information header
  587.  */
  588. procheader(name)
  589. char *name;
  590. {
  591.     register char *openmode, *p;
  592.     static dummy;
  593.     struct stat f;
  594.  
  595.     /* set default parameters and overrides */
  596.     openmode = "w";
  597.     Thisbinary = (!Rxascii) || Rxbinary;
  598.     if (zconv == ZCBIN && Lzconv != ZCRESUM)
  599.         Lzconv = zconv;            /* Remote Binary override */
  600.     if (Lzconv)
  601.         zconv = Lzconv;
  602.     if (Lzmanag)
  603.         zmanag = Lzmanag;
  604.  
  605.     /*
  606.      *  Process ZMODEM remote file management requests
  607.      */
  608.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  609.         Thisbinary = 0;
  610.     if (zconv == ZCBIN)    /* Remote Binary override */
  611.         Thisbinary = TRUE;
  612.     else if (zmanag == ZMAPND)
  613.         openmode = "a";
  614.  
  615.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  616.  
  617.     if (!name || !*name)
  618.         return OK;
  619.  
  620.     p = name + 1 + strlen(name);
  621.     if (*p) {    /* file coming from Unix or DOS system */
  622.         sscanf(p, "%ld%lo%o%lo%d%ld%d%d",
  623.           &Bytesleft, &Modtime, &Filemode,
  624.           &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  625.         if (Filemode & UNIXFILE)
  626.             ++Thisbinary;
  627.         if (Verbose) {
  628.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  629.               name, Bytesleft, Modtime, Filemode);
  630.             fprintf(stderr,  "YMODEM header: %s\n", p);
  631.         }
  632.     }
  633.  
  634.  
  635.     else {        /* File coming from CP/M system */
  636.         for (p=name; *p; ++p)        /* change / to _ */
  637.             if ( *p == '/')
  638.                 *p = '_';
  639.  
  640.         if ( *--p == '.')        /* zap trailing period */
  641.             *p = 0;
  642.     }
  643.  
  644.     strcpy(Pathname, name);
  645.     checkpath(name);
  646.  
  647.     if (*name && stat(name, &f)!= -1) {
  648.         zmanag &= ZMMASK;
  649.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  650.         if (Thisbinary && zconv==ZCRESUM) {
  651.             rxbytes = f.st_size & ~511;
  652.             if (Bytesleft < rxbytes) {
  653.                 rxbytes = 0;  goto doopen;
  654.             } else
  655.                 openit(name, "r+");
  656.             if ( !fout)
  657.                 return ZFERR;
  658.             if (fseek(fout, rxbytes, 0)) {
  659.                 closeit();
  660.                 return ZFERR;
  661.             }
  662.             vfile("Crash recovery at %ld", rxbytes);
  663.             return 0;
  664.         }
  665.         else if ((zmanag==ZMNEW) ||
  666.           ((zmanag==ZMNEWL) && Bytesleft <= f.st_size) ) {
  667.             if ((f.st_mtime+1) >= Modtime)
  668.                 goto skipfile;
  669.             goto doopen;
  670.         }
  671.         switch (zmanag & ZMMASK) {
  672.         case ZMCLOB:
  673.         case ZMAPND:
  674.             goto doopen;
  675.         default:
  676.             goto skipfile;
  677.         }
  678.     } else if (zmanag & ZMSKNOLOC) {
  679. skipfile:
  680.         vfile("Skipping %s", name);
  681.         return ZSKIP;
  682.     }
  683. doopen:
  684.     openit(name, openmode);
  685. #ifdef MD
  686.     if ( !fout)
  687.         if (make_dirs(name))
  688.             openit(name, openmode);
  689. #endif
  690.     if ( !fout)
  691.         return ZFERR;
  692.     return 0;
  693. }
  694.  
  695. openit(name, openmode)
  696. char *name, *openmode;
  697. {
  698.     fout = fopen(name, openmode);
  699. }
  700.  
  701. #ifdef MD
  702. /*
  703.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  704.  */
  705.  
  706. /*
  707.  * After a file/link/symlink/dir creation has failed, see if
  708.  * it's because some required directory was not present, and if
  709.  * so, create all required dirs.
  710.  */
  711. make_dirs(pathname)
  712. register char *pathname;
  713. {
  714.     register char *p;        /* Points into path */
  715.     int madeone = 0;        /* Did we do anything yet? */
  716.     int save_errno = errno;        /* Remember caller's errno */
  717.  
  718.     if (errno != ENOENT)
  719.         return 0;        /* Not our problem */
  720.  
  721.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  722.         /* Avoid mkdir of empty string, if leading or double '/' */
  723.         if (p == pathname || p[-1] == '/')
  724.             continue;
  725.         /* Avoid mkdir where last part of path is '.' */
  726.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  727.             continue;
  728.         *p = 0;                /* Truncate the path there */
  729.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  730.             vfile("Made directory %s\n", pathname);
  731.             madeone++;        /* Remember if we made one */
  732.             *p = '/';
  733.             continue;
  734.         }
  735.         *p = '/';
  736.         if (errno == EEXIST)        /* Directory already exists */
  737.             continue;
  738.         /*
  739.          * Some other error in the mkdir.  We return to the caller.
  740.          */
  741.         break;
  742.     }
  743.     errno = save_errno;        /* Restore caller's errno */
  744.     return madeone;            /* Tell them to retry if we made one */
  745. }
  746.  
  747. #if (MD != 2)
  748. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  749. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  750. #define TERM_VALUE(status)    ((status) >> 8)
  751. /*
  752.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  753.  */
  754. mkdir(dpath, dmode)
  755. char *dpath;
  756. int dmode;
  757. {
  758.     int cpid, status;
  759.     struct stat statbuf;
  760.  
  761.     if (stat(dpath,&statbuf) == 0) {
  762.         errno = EEXIST;        /* Stat worked, so it already exists */
  763.         return -1;
  764.     }
  765.  
  766.     /* If stat fails for a reason other than non-existence, return error */
  767.     if (errno != ENOENT) return -1; 
  768.  
  769.     switch (cpid = fork()) {
  770.  
  771.     case -1:            /* Error in fork() */
  772.         return(-1);        /* Errno is set already */
  773.  
  774.     case 0:                /* Child process */
  775.         /*
  776.          * Cheap hack to set mode of new directory.  Since this
  777.          * child process is going away anyway, we zap its umask.
  778.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  779.          * directory.  Does anybody care?
  780.          */
  781.         status = umask(0);    /* Get current umask */
  782.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  783.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  784.         _exit(2);        /* Can't exec /bin/mkdir */
  785.     
  786.     default:            /* Parent process */
  787.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  788.     }
  789.  
  790.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  791.         errno = EIO;        /* We don't know why, but */
  792.         return -1;        /* /bin/mkdir failed */
  793.     }
  794.  
  795.     return 0;
  796. }
  797. #endif /* MD != 2 */
  798. #endif /* MD */
  799.  
  800. /*
  801.  * Putsec writes the n characters of buf to receive file fout.
  802.  *  If not in binary mode, carriage returns, and all characters
  803.  *  starting with CPMEOF are discarded.
  804.  */
  805. putsec(buf, n)
  806. char *buf;
  807. register n;
  808. {
  809.     register char *p;
  810.  
  811.     if (n == 0)
  812.         return OK;
  813.     if (Thisbinary) {
  814.         for (p=buf; --n>=0; )
  815.             putc( *p++, fout);
  816.     }
  817.     else {
  818.         if (Eofseen)
  819.             return OK;
  820.         for (p=buf; --n>=0; ++p ) {
  821.             if ( *p == '\r')
  822.                 continue;
  823.             if (*p == CPMEOF) {
  824.                 Eofseen=TRUE; return OK;
  825.             }
  826.             putc(*p ,fout);
  827.         }
  828.     }
  829.     return OK;
  830. }
  831.  
  832. /*
  833.  * substr(string, token) searches for token in string s
  834.  * returns pointer to token within string if found, NULL otherwise
  835.  */
  836. char *
  837. substr(s, t)
  838. register char *s,*t;
  839. {
  840.     register char *ss,*tt;
  841.     /* search for first char of token */
  842.     for (ss=s; *s; s++)
  843.         if (*s == *t)
  844.             /* compare token with substring */
  845.             for (ss=s,tt=t; ;) {
  846.                 if (*tt == 0)
  847.                     return s;
  848.                 if (*ss++ != *tt++)
  849.                     break;
  850.             }
  851.     return NULL;
  852. }
  853.  
  854.  
  855. /*
  856.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  857.  * If called as rb use YMODEM protocol
  858.  */
  859. chkinvok(s)
  860. char *s;
  861. {
  862.     register char *p;
  863.  
  864.     p = s;
  865.     while (*p == '-')
  866.         s = ++p;
  867.     while (*p)
  868.         if (*p++ == '/')
  869.             s = p;
  870.     if (*s == 'v') {
  871.         Verbose=1; ++s;
  872.     }
  873.     Progname = s;
  874.     if (s[0]=='r' && s[1]=='z')
  875.         Batch = TRUE;
  876.     if (s[0]=='r' && s[1]=='c')
  877.         Crcflg = TRUE;
  878.     if (s[0]=='r' && s[1]=='b')
  879.         Batch = Nozmodem = TRUE;
  880. }
  881.  
  882. /*
  883.  * Totalitarian Communist pathname processing
  884.  */
  885. checkpath(name)
  886. char *name;
  887. {
  888.     if (Restricted) {
  889.         if (fopen(name, "r") != NULL) {
  890.             canit();
  891.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  892.             bibi(-1);
  893.         }
  894.         /* restrict pathnames to current tree or uucppublic */
  895.         if ( substr(name, "../")
  896.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  897.             canit();
  898.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  899.             bibi(-1);
  900.         }
  901.     }
  902. }
  903. /*
  904.  * Ack a ZFIN packet, let byegones be byegones
  905.  */
  906. void
  907. ackbibi()
  908. {
  909.     register n;
  910.  
  911.     vfile("ackbibi:");
  912.     Readnum = 1;
  913.     stohdr(0L);
  914.     for (n=3; --n>=0; ) {
  915.         purgeline();
  916.         zshhdr(4,ZFIN, Txhdr);
  917.         switch (readline(100)) {
  918.         case 'O':
  919.             readline(1);    /* Discard 2nd 'O' */
  920.             vfile("ackbibi complete");
  921.             return;
  922.         case RCDO:
  923.             return;
  924.         case TIMEOUT:
  925.         default:
  926.             break;
  927.         }
  928.     }
  929. }
  930.  
  931.  
  932. /*
  933.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  934.  *  Handles ZSINIT frame
  935.  *  Return ZFILE if Zmodem filename received, -1 on error,
  936.  *   ZCOMPL if transaction finished,  else 0
  937.  */
  938. tryz()
  939. {
  940.     register c, n;
  941.     register cmdzack1flg;
  942.  
  943.     if (Nozmodem)        /* Check for "rb" program name */
  944.         return 0;
  945.  
  946.  
  947.     for (n=15; --n>=0; ) {
  948.         /* Set buffer length (0) and capability flags */
  949. #ifdef SEGMENTS
  950.         stohdr(SEGMENTS*1024L);
  951. #else
  952.         stohdr(0L);
  953. #endif
  954. #ifdef CANBREAK
  955.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  956. #else
  957.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  958. #endif
  959.         if (Zctlesc)
  960.             Txhdr[ZF0] |= TESCCTL;
  961.         Txhdr[ZF0] |= CANRLE;
  962.         Txhdr[ZF1] = CANVHDR;
  963.         /* tryzhdrtype may == ZRINIT */
  964.         zshhdr(4,tryzhdrtype, Txhdr);
  965.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  966.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  967. again:
  968.         switch (zgethdr(Rxhdr)) {
  969.         case ZRQINIT:
  970.             if (Rxhdr[ZF3] & 0x80)
  971.                 Usevhdrs = 1;    /* we can var header */
  972.             continue;
  973.         case ZEOF:
  974.             continue;
  975.         case TIMEOUT:
  976.             continue;
  977.         case ZFILE:
  978.             zconv = Rxhdr[ZF0];
  979.             zmanag = Rxhdr[ZF1];
  980.             ztrans = Rxhdr[ZF2];
  981.             if (Rxhdr[ZF3] & ZCANVHDR)
  982.                 Usevhdrs = TRUE;
  983.             tryzhdrtype = ZRINIT;
  984.             c = zrdata(secbuf, 1024);
  985.             if (c == GOTCRCW)
  986.                 return ZFILE;
  987.             zshhdr(4,ZNAK, Txhdr);
  988.             goto again;
  989.         case ZSINIT:
  990.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  991.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  992.                 stohdr(1L);
  993.                 zshhdr(4,ZACK, Txhdr);
  994.                 goto again;
  995.             }
  996.             zshhdr(4,ZNAK, Txhdr);
  997.             goto again;
  998.         case ZFREECNT:
  999.             stohdr(getfree());
  1000.             zshhdr(4,ZACK, Txhdr);
  1001.             goto again;
  1002.         case ZCOMMAND:
  1003.             cmdzack1flg = Rxhdr[ZF0];
  1004.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1005.                 void exec2();
  1006.  
  1007.                 if (cmdzack1flg & ZCACK1)
  1008.                     stohdr(0L);
  1009.                 else
  1010.                     stohdr((long)sys2(secbuf));
  1011.                 purgeline();    /* dump impatient questions */
  1012.                 do {
  1013.                     zshhdr(4,ZCOMPL, Txhdr);
  1014.                 }
  1015.                 while (++errors<20 && zgethdr(Rxhdr) != ZFIN);
  1016.                 ackbibi();
  1017.                 if (cmdzack1flg & ZCACK1)
  1018.                     exec2(secbuf);
  1019.                 return ZCOMPL;
  1020.             }
  1021.             zshhdr(4,ZNAK, Txhdr); goto again;
  1022.         case ZCOMPL:
  1023.             goto again;
  1024.         default:
  1025.             continue;
  1026.         case ZFIN:
  1027.             ackbibi(); return ZCOMPL;
  1028.         case ZCAN:
  1029.             return ERROR;
  1030.         }
  1031.     }
  1032.     return 0;
  1033. }
  1034.  
  1035. /*
  1036.  * Receive 1 or more files with ZMODEM protocol
  1037.  */
  1038. rzfiles()
  1039. {
  1040.     register c;
  1041.  
  1042.     for (;;) {
  1043.         switch (c = rzfile()) {
  1044.         case ZEOF:
  1045.         case ZSKIP:
  1046.             switch (tryz()) {
  1047.             case ZCOMPL:
  1048.                 return OK;
  1049.             default:
  1050.                 return ERROR;
  1051.             case ZFILE:
  1052.                 break;
  1053.             }
  1054.             continue;
  1055.         default:
  1056.             return c;
  1057.         case ERROR:
  1058.             return ERROR;
  1059.         }
  1060.     }
  1061.     /* NOTREACHED */
  1062. }
  1063.  
  1064. /*
  1065.  * Receive a file with ZMODEM protocol
  1066.  *  Assumes file name frame is in secbuf
  1067.  */
  1068. rzfile()
  1069. {
  1070.     register c, n;
  1071.  
  1072.     Eofseen=FALSE;
  1073.     n = 20; rxbytes = 0l;
  1074.  
  1075.     if (c = procheader(secbuf)) {
  1076.         return (tryzhdrtype = c);
  1077.     }
  1078.  
  1079.     for (;;) {
  1080. #ifdef SEGMENTS
  1081.         chinseg = 0;
  1082. #endif
  1083.         stohdr(rxbytes);
  1084.         zshhdr(4,ZRPOS, Txhdr);
  1085. nxthdr:
  1086.         switch (c = zgethdr(Rxhdr)) {
  1087.         default:
  1088.             vfile("rzfile: Wrong header %d", c);
  1089.             if ( --n < 0) {
  1090.                 sprintf(endmsg, "rzfile: Wrong header %d", c);
  1091.                 return ERROR;
  1092.             }
  1093.             continue;
  1094.         case ZCAN:
  1095.             sprintf(endmsg, "Sender CANcelled");
  1096.             return ERROR;
  1097.         case ZNAK:
  1098. #ifdef SEGMENTS
  1099.             putsec(secbuf, chinseg);
  1100.             chinseg = 0;
  1101. #endif
  1102.             if ( --n < 0) {
  1103.                 sprintf(endmsg, "rzfile: got ZNAK", c);
  1104.                 return ERROR;
  1105.             }
  1106.             continue;
  1107.         case TIMEOUT:
  1108. #ifdef SEGMENTS
  1109.             putsec(secbuf, chinseg);
  1110.             chinseg = 0;
  1111. #endif
  1112.             if ( --n < 0) {
  1113.                 sprintf(endmsg, "rzfile: TIMEOUT", c);
  1114.                 return ERROR;
  1115.             }
  1116.             continue;
  1117.         case ZFILE:
  1118.             zrdata(secbuf, 1024);
  1119.             continue;
  1120.         case ZEOF:
  1121. #ifdef SEGMENTS
  1122.             putsec(secbuf, chinseg);
  1123.             chinseg = 0;
  1124. #endif
  1125.             if (rclhdr(Rxhdr) != rxbytes) {
  1126.                 /*
  1127.                  * Ignore eof if it's at wrong place - force
  1128.                  *  a timeout because the eof might have gone
  1129.                  *  out before we sent our zrpos.
  1130.                  */
  1131.                 errors = 0;  goto nxthdr;
  1132.             }
  1133.             if (closeit()) {
  1134.                 tryzhdrtype = ZFERR;
  1135.                 vfile("rzfile: closeit returned <> 0");
  1136.                 sprintf(endmsg,"Error closing file");
  1137.                 return ERROR;
  1138.             }
  1139.             vfile("rzfile: normal EOF");
  1140.             return c;
  1141.         case ERROR:    /* Too much garbage in header search error */
  1142. #ifdef SEGMENTS
  1143.             putsec(secbuf, chinseg);
  1144.             chinseg = 0;
  1145. #endif
  1146.             if ( --n < 0) {
  1147.                 sprintf(endmsg, "Persistent CRC or other ERROR");
  1148.                 return ERROR;
  1149.             }
  1150.             zmputs(Attn);
  1151.             continue;
  1152.         case ZSKIP:
  1153. #ifdef SEGMENTS
  1154.             putsec(secbuf, chinseg);
  1155.             chinseg = 0;
  1156. #endif
  1157.             Modtime = 1;
  1158.             closeit();
  1159.             sprintf(endmsg, "Sender SKIPPED file");
  1160.             return c;
  1161.         case ZDATA:
  1162.             if (rclhdr(Rxhdr) != rxbytes) {
  1163.                 if ( --n < 0) {
  1164.                     sprintf(endmsg,"Data has bad addr");
  1165.                     return ERROR;
  1166.                 }
  1167. #ifdef SEGMENTS
  1168.                 putsec(secbuf, chinseg);
  1169.                 chinseg = 0;
  1170. #endif
  1171.                 zmputs(Attn);  continue;
  1172.             }
  1173. moredata:
  1174.             if (Verbose>1)
  1175.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1176.                   rxbytes, Crc32r?" CRC-32":"");
  1177. #ifdef SEGMENTS
  1178.             if (chinseg >= (1024 * SEGMENTS)) {
  1179.                 putsec(secbuf, chinseg);
  1180.                 chinseg = 0;
  1181.             }
  1182.             switch (c = zrdata(secbuf+chinseg, 1024))
  1183. #else
  1184.             switch (c = zrdata(secbuf, 1024))
  1185. #endif
  1186.             {
  1187.             case ZCAN:
  1188. #ifdef SEGMENTS
  1189.                 putsec(secbuf, chinseg);
  1190.                 chinseg = 0;
  1191. #endif
  1192.                 sprintf(endmsg, "Sender CANcelled");
  1193.                 return ERROR;
  1194.             case ERROR:    /* CRC error */
  1195. #ifdef SEGMENTS
  1196.                 putsec(secbuf, chinseg);
  1197.                 chinseg = 0;
  1198. #endif
  1199.                 if ( --n < 0) {
  1200.                     sprintf(endmsg, "Persistent CRC or other ERROR");
  1201.                     return ERROR;
  1202.                 }
  1203.                 zmputs(Attn);
  1204.                 continue;
  1205.             case TIMEOUT:
  1206. #ifdef SEGMENTS
  1207.                 putsec(secbuf, chinseg);
  1208.                 chinseg = 0;
  1209. #endif
  1210.                 if ( --n < 0) {
  1211.                     sprintf(endmsg, "TIMEOUT");
  1212.                     return ERROR;
  1213.                 }
  1214.                 continue;
  1215.             case GOTCRCW:
  1216.                 n = 20;
  1217. #ifdef SEGMENTS
  1218.                 chinseg += Rxcount;
  1219.                 putsec(secbuf, chinseg);
  1220.                 chinseg = 0;
  1221. #else
  1222.                 putsec(secbuf, Rxcount);
  1223. #endif
  1224.                 rxbytes += Rxcount;
  1225.                 stohdr(rxbytes);
  1226.                 sendline(XON);
  1227.                 zshhdr(4,ZACK, Txhdr);
  1228.                 goto nxthdr;
  1229.             case GOTCRCQ:
  1230.                 n = 20;
  1231. #ifdef SEGMENTS
  1232.                 chinseg += Rxcount;
  1233. #else
  1234.                 putsec(secbuf, Rxcount);
  1235. #endif
  1236.                 rxbytes += Rxcount;
  1237.                 stohdr(rxbytes);
  1238.                 zshhdr(4,ZACK, Txhdr);
  1239.                 goto moredata;
  1240.             case GOTCRCG:
  1241.                 n = 20;
  1242. #ifdef SEGMENTS
  1243.                 chinseg += Rxcount;
  1244. #else
  1245.                 putsec(secbuf, Rxcount);
  1246. #endif
  1247.                 rxbytes += Rxcount;
  1248.                 goto moredata;
  1249.             case GOTCRCE:
  1250.                 n = 20;
  1251. #ifdef SEGMENTS
  1252.                 chinseg += Rxcount;
  1253. #else
  1254.                 putsec(secbuf, Rxcount);
  1255. #endif
  1256.                 rxbytes += Rxcount;
  1257.                 goto nxthdr;
  1258.             }
  1259.         }
  1260.     }
  1261. }
  1262.  
  1263.  
  1264. /*
  1265.  * Close the receive dataset, return OK or ERROR
  1266.  */
  1267. closeit()
  1268. {
  1269.     time_t time();
  1270.  
  1271.     if (fclose(fout)==ERROR) {
  1272.         fprintf(stderr, "file close ERROR\n");
  1273.         return ERROR;
  1274.     }
  1275.     if (Modtime) {
  1276.         timep[0] = time(NULL);
  1277.         timep[1] = Modtime;
  1278.         utime(Pathname, timep);
  1279.     }
  1280.     if (
  1281. #ifdef POSIX
  1282.     S_ISREG(Filemode)
  1283. #else
  1284.     (Filemode&S_IFMT) == S_IFREG
  1285. #endif
  1286.     )
  1287.         chmod(Pathname, (unsigned short)(07777 & Filemode));
  1288.     return OK;
  1289. }
  1290.  
  1291.  
  1292. /*
  1293.  * Strip leading ! if present, do shell escape. 
  1294.  */
  1295. sys2(s)
  1296. register char *s;
  1297. {
  1298.     if (*s == '!')
  1299.         ++s;
  1300.     return system(s);
  1301. }
  1302. /*
  1303.  * Strip leading ! if present, do exec.
  1304.  */
  1305. void
  1306. exec2(s)
  1307. register char *s;
  1308. {
  1309.     if (*s == '!')
  1310.         ++s;
  1311.     mode(0);
  1312.     execl("/bin/sh", "sh", "-c", s);
  1313. }
  1314.  
  1315. /* End of rz.c */
  1316.